package org.summerframework.core.base.service.impl;

import org.summerframework.core.base.dao.BaseDAO;
import org.summerframework.core.base.dto.BaseDO;
import org.summerframework.core.base.dto.BaseDTO;
import org.summerframework.core.base.result.DefaultResultCode;
import org.summerframework.core.base.service.BaseService;
import org.summerframework.core.check.Insert;
import org.summerframework.core.check.Update;
import org.summerframework.core.check.ValidationUtils;
import org.summerframework.core.exception.WebException;
import org.summerframework.core.jackson.SelectByIdSerializer;
import org.summerframework.core.util.ClassGenricTypeBeanUtils;
import org.summerframework.core.util.ConvertUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import javax.validation.groups.Default;
import java.util.ArrayList;
import java.util.List;

/**
 * 添加,自动完成
 * <p>
 * {@link AbstractBaseService}
 * {@link #insert(BaseDTO)} }
 * {@link #updateById(BaseDTO)}
 * {@link #selectById(Long)}
 * {@link #deleteById(Long)}
 *
 * @param <T> 对应的DTO对象
 * @author 石超
 * @version 1.0.0
 */
public abstract class AbstractBaseService<DAO extends BaseDAO<D>, T extends BaseDTO, D extends BaseDO> implements BaseService<T> {

    @Autowired(required = false)
    protected DAO baseDAO;

    public final Logger log = LoggerFactory.getLogger(getClass());

    /**
     * 获取dao,多态
     *
     * @return 返回值必须继承BaseDAO
     */
    protected DAO getDAO() {
        if (baseDAO == null) {
            throw DefaultResultCode.SYSTEM_ERROR_FORMAT.format("DAO获取异常");
        }

        return baseDAO;
    }

    @Override
    public Integer deleteById(Long id) {
        return getDAO().deleteById(id);
    }

    @Override
    public T insert(T baseDTO) {
        // 验证参数
        check(BASE_OP.INSERT, baseDTO);
        D baseDO = fromDTO2DO(baseDTO);
        getDAO().insert(baseDO);
        baseDTO.setId(baseDO.getId());

        return baseDTO;
    }

    @Override
    public Integer updateById(T baseDTO) {
        // 验证参数
        check(BASE_OP.UPDATE, baseDTO);

        return getDAO().updateById(fromDTO2DO(baseDTO));
    }

    @Override
    public T selectById(Long id) {
        return fromDO2DTO(getDAO().selectById(id));
    }

    /**
     * 根据id判断实体是否存在
     *
     * @param id 实体id
     */
    @Override
    public boolean isExistById(Long id) {
        return getDAO().selectById(id) != null;
    }

    @Override
    public boolean check(BASE_OP baseOp, T baseDTO) throws WebException {
        switch (baseOp) {
            case INSERT:
                ValidationUtils.validate(baseDTO, Default.class, Insert.class);
                break;
            case UPDATE:
                ValidationUtils.validate(baseDTO, Default.class, Update.class);

                if (!isUpdate(baseDTO)) {
                    throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
                }
                break;
            case DELETE:
                if (!isUpdate(baseDTO)) {
                    throw new WebException(DefaultResultCode.ILLEGAL_ARGUMENT);
                }
                break;
            default:
                break;
        }

        return true;
    }

    public T fromDO2DTO(BaseDO baseDO) throws WebException {
        return fromDO2DTO(baseDO, (T) ClassGenricTypeBeanUtils.newInstance(this.getClass(), BaseService.class, 0));
    }

    public <DTO extends T> DTO fromDO2DTO(BaseDO baseDO, DTO baseDTO) throws WebException {
        if (baseDO == null) {
            return null;
        }

        return SelectByIdSerializer.serializer(ConvertUtils.copyProperties(baseDTO, baseDO));
    }

    public D fromDTO2DO(T baseDTO) throws WebException {
        if (baseDTO == null) {
            return null;
        }

        return ConvertUtils.copyProperties((D) ClassGenricTypeBeanUtils.newInstance(getDAO().getClass(), BaseDAO.class, 0), baseDTO);
    }

    public List<D> fromDTO2DO(List<T> baseDTOs) throws WebException {
        List<D> list = new ArrayList<>();
        if (CollectionUtils.isEmpty(baseDTOs)) {
            return list;
        }
        for (T d : baseDTOs) {
            list.add(fromDTO2DO(d));
        }
        return list;
    }

    public List<T> fromDO2DTO(List<? extends BaseDO> baseDOs) throws WebException {
        List<T> list = new ArrayList<>();

        if (CollectionUtils.isEmpty(baseDOs)) {
            return list;
        }

        for (BaseDO d : baseDOs) {
            list.add(fromDO2DTO(d));
        }

        return list;
    }

    @Override
    public T saveOrUpdate(T record) {
        if (isUpdate(record)) {
            updateById(record);
            return record;
        }
        return insert(record);
    }

    protected boolean isUpdate(T record) {
        return record != null && record.getId() != null;
    }
}
